package anyVehicle;

import java.io.File;
import java.lang.reflect.Field;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import net.minecraft.src.AxisAlignedBB;
import net.minecraft.src.Block;
import net.minecraft.src.Chunk;
import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityLightningBolt;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.EnumSkyBlock;
import net.minecraft.src.IBlockAccess;
import net.minecraft.src.Material;
import net.minecraft.src.MathHelper;
import net.minecraft.src.ModLoader;
import net.minecraft.src.Vec3D;
import net.minecraft.src.World;
import net.minecraft.src.WorldSettings;

import org.lwjgl.BufferUtils;
import org.lwjgl.util.vector.Matrix4f;

public class VehicleBlocks extends World implements IBlockAccess {

	public static int MAX_LENGTH = 100;
	public static int MAX_HEIGHT = 100;
	public static int MAX_WIDTH = 100;

	public World parentWorld;
	public Vehicle parentVehicle;
	
	int lightUpdateBlockList2[];

	FloatBuffer matrixData = BufferUtils.createFloatBuffer(16);
	Matrix4f matrix = new Matrix4f();
	private String vehicleID;

	// public VehicleRenderGlobal vehicleRenderGlobal;

	public VehicleBlocks(World parentWorld, Vehicle parentVehicle, String vehicleID) {
		super(
				new VehicleSaveHandler(new File(ModLoader.getMinecraftInstance().mcDataDir, "saves"), parentWorld.getWorldInfo().getWorldName(), vehicleID,
						false), vehicleID, new VehicleWorldProvider(), new WorldSettings(0L, 0, false, true));
		this.parentWorld = parentWorld;
		this.parentVehicle = parentVehicle;
		worldInfo = new VehicleWorldInfo(worldInfo, parentWorld);
		this.vehicleID = vehicleID;
		try {
			
			Field f = World.class.getDeclaredField("lightUpdateBlockList");
			f.setAccessible(true);
			lightUpdateBlockList2 = (int[]) f.get(this);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// vehicleRenderGlobal = new
		// VehicleRenderGlobal(ModLoader.getMinecraftInstance(),
		// ModLoader.getMinecraftInstance().renderEngine, parentVehicle);
		// addWorldAccess(vehicleRenderGlobal);

	}

	public VehicleBlocks(World parentWorld, Vehicle parentVehicle) {
		this(parentWorld, parentVehicle, UUID.randomUUID().toString());

	}

	@Override
	public void tick() {

		int slSubst = calculateSkylightSubtracted(1.0F);
		if (slSubst != skylightSubtracted) {
			skylightSubtracted = slSubst;
		}

		tickUpdates(false);
		updateBlocksAndPlayCaveSounds();
	}
	
    private int computeSkyLightValue(int i, int j, int k, int l, int i1, int j1)
    {
        int k1 = 0;
        if(canBlockSeeTheSky(j, k, l))
        {
            k1 = 15;
        } else
        {
            if(j1 == 0)
            {
                j1 = 1;
            }
            for(int l1 = 0; l1 < 6; l1++)
            {
                int i2 = (l1 % 2) * 2 - 1;
                int j2 = j + (((l1 / 2) % 3) / 2) * i2;
                int k2 = k + (((l1 / 2 + 1) % 3) / 2) * i2;
                int l2 = l + (((l1 / 2 + 2) % 3) / 2) * i2;
                int i3 = getSavedLightValue(EnumSkyBlock.Sky, j2, k2, l2) - j1;
                if(i3 > k1)
                {
                    k1 = i3;
                }
            }

        }
        return k1;
    }

    private int computeBlockLightValue(int i, int j, int k, int l, int i1, int j1)
    {
    	int k1=Block.lightValue[i1];
        int l1 = getSavedLightValue(EnumSkyBlock.Block, j - 1, k, l) - j1;
        int i2 = getSavedLightValue(EnumSkyBlock.Block, j + 1, k, l) - j1;
        int j2 = getSavedLightValue(EnumSkyBlock.Block, j, k - 1, l) - j1;
        int k2 = getSavedLightValue(EnumSkyBlock.Block, j, k + 1, l) - j1;
        int l2 = getSavedLightValue(EnumSkyBlock.Block, j, k, l - 1) - j1;
        int i3 = getSavedLightValue(EnumSkyBlock.Block, j, k, l + 1) - j1;
        if(l1 > k1)
        {
            k1 = l1;
        }
        if(i2 > k1)
        {
            k1 = i2;
        }
        if(j2 > k1)
        {
            k1 = j2;
        }
        if(k2 > k1)
        {
            k1 = k2;
        }
        if(l2 > k1)
        {
            k1 = l2;
        }
        if(i3 > k1)
        {
            k1 = i3;
        }
        return k1;
    }

    @Override
	public void updateLightByType(EnumSkyBlock enumskyblock, int i, int j, int k) {
		int l = 0;
		int i1 = 0;
		int j1 = getSavedLightValue(enumskyblock, i, j, k);
		int l1 = 0;
		int j2 = j1;
		int i3 = getBlockId(i, j, k);
		int l3 = Block.lightOpacity[i3];
		if (l3 == 0) {
			l3 = 1;
		}
		int k4 = 0;
		if (enumskyblock == EnumSkyBlock.Sky) {
			k4 = computeSkyLightValue(j2, i, j, k, i3, l3);
		} else {
			k4 = computeBlockLightValue(j2, i, j, k, i3, l3);
		}
		l1 = k4;
		if (l1 > j1) {
			lightUpdateBlockList2[i1++] = 0x20820;
		} else if (l1 < j1) {
			if (enumskyblock == EnumSkyBlock.Block)
				;
			lightUpdateBlockList2[i1++] = 0x20820 + (j1 << 18);
			do {
				if (l >= i1) {
					break;
				}
				int k2 = lightUpdateBlockList2[l++];
				int j3 = ((k2 & 0x3f) - 32) + i;
				int i4 = ((k2 >> 6 & 0x3f) - 32) + j;
				int l4 = ((k2 >> 12 & 0x3f) - 32) + k;
				int j5 = k2 >> 18 & 0xf;
				int l5 = getSavedLightValue(enumskyblock, j3, i4, l4);
				if (l5 == j5) {
					setLightValue(enumskyblock, j3, i4, l4, 0);
					if (--j5 > 0) {
						int k6 = j3 - i;
						int i7 = i4 - j;
						int k7 = l4 - k;
						if (k6 < 0) {
							k6 = -k6;
						}
						if (i7 < 0) {
							i7 = -i7;
						}
						if (k7 < 0) {
							k7 = -k7;
						}
						if (k6 + i7 + k7 < 17) {
							int i8 = 0;
							while (i8 < 6) {
								int j8 = (i8 % 2) * 2 - 1;
								int k8 = j3 + (((i8 / 2) % 3) / 2) * j8;
								int l8 = i4 + (((i8 / 2 + 1) % 3) / 2) * j8;
								int i9 = l4 + (((i8 / 2 + 2) % 3) / 2) * j8;
								int i6 = getSavedLightValue(enumskyblock, k8, l8, i9);
								if (i6 == j5) {
									lightUpdateBlockList2[i1++] = (k8 - i) + 32 + ((l8 - j) + 32 << 6) + ((i9 - k) + 32 << 12) + (j5 << 18);
								}
								i8++;
							}
						}
					}
				}
			} while (true);
			l = 0;
		}
		do {
			if (l >= i1) {
				break;
			}
			int k1 = lightUpdateBlockList2[l++];
			int i2 = ((k1 & 0x3f) - 32) + i;
			int l2 = ((k1 >> 6 & 0x3f) - 32) + j;
			int k3 = ((k1 >> 12 & 0x3f) - 32) + k;
			int j4 = getSavedLightValue(enumskyblock, i2, l2, k3);
			int i5 = getBlockId(i2, l2, k3);
			int k5 = Block.lightOpacity[i5];
			if (k5 == 0) {
				k5 = 1;
			}
			int j6 = 0;
			if (enumskyblock == EnumSkyBlock.Sky) {
				j6 = computeSkyLightValue(j4, i2, l2, k3, i5, k5);
			} else {
				j6 = computeBlockLightValue(j4, i2, l2, k3, i5, k5);
			}
			if (j6 != j4) {
				setLightValue(enumskyblock, i2, l2, k3, j6);
				if (j6 > j4) {
					int l6 = i2 - i;
					int j7 = l2 - j;
					int l7 = k3 - k;
					if (l6 < 0) {
						l6 = -l6;
					}
					if (j7 < 0) {
						j7 = -j7;
					}
					if (l7 < 0) {
						l7 = -l7;
					}
					if (l6 + j7 + l7 < 17 && i1 < lightUpdateBlockList2.length - 6) {
						if (getSavedLightValue(enumskyblock, i2 - 1, l2, k3) < j6) {
							lightUpdateBlockList2[i1++] = (i2 - 1 - i) + 32 + ((l2 - j) + 32 << 6) + ((k3 - k) + 32 << 12);
						}
						if (getSavedLightValue(enumskyblock, i2 + 1, l2, k3) < j6) {
							lightUpdateBlockList2[i1++] = ((i2 + 1) - i) + 32 + ((l2 - j) + 32 << 6) + ((k3 - k) + 32 << 12);
						}
						if (getSavedLightValue(enumskyblock, i2, l2 - 1, k3) < j6) {
							lightUpdateBlockList2[i1++] = (i2 - i) + 32 + ((l2 - 1 - j) + 32 << 6) + ((k3 - k) + 32 << 12);
						}
						if (getSavedLightValue(enumskyblock, i2, l2 + 1, k3) < j6) {
							lightUpdateBlockList2[i1++] = (i2 - i) + 32 + (((l2 + 1) - j) + 32 << 6) + ((k3 - k) + 32 << 12);
						}
						if (getSavedLightValue(enumskyblock, i2, l2, k3 - 1) < j6) {
							lightUpdateBlockList2[i1++] = (i2 - i) + 32 + ((l2 - j) + 32 << 6) + ((k3 - 1 - k) + 32 << 12);
						}
						if (getSavedLightValue(enumskyblock, i2, l2, k3 + 1) < j6) {
							lightUpdateBlockList2[i1++] = (i2 - i) + 32 + ((l2 - j) + 32 << 6) + (((k3 + 1) - k) + 32 << 12);
						}
					}
				}
			}
		} while (true);
	}


	public int calculateSkylightSubtracted(float f) {
		if (parentWorld == null) {
			return super.calculateSkylightSubtracted(f);
		} else {
			return parentWorld.calculateSkylightSubtracted(f);
		}
	}


	@Override
	public boolean isDaytime() {
		if (parentWorld == null) {
			return super.isDaytime();
		} else {
			return parentWorld.isDaytime();
		}
	}

	@Override
	public Vec3D getSkyColor(Entity entity, float f) {
		if (parentWorld == null) {
			return super.getSkyColor(entity, f);
		} else {
			return parentWorld.getSkyColor(entity, f);
		}
	}

	@Override
	public float getCelestialAngle(float f) {
		if (parentWorld == null) {
			return super.getCelestialAngle(f);
		} else {
			return parentWorld.getCelestialAngle(f);
		}
	}

	@Override
	public float getStarBrightness(float f) {
		if (parentWorld == null) {
			return super.getStarBrightness(f);
		}
		return parentWorld.getStarBrightness(f);
	}

	public String getVehicleID() {
		return vehicleID;
	}
	
	@Override
    public List getCollidingBoundingBoxes(Entity entity, AxisAlignedBB axisalignedbb)
    {
        ArrayList collidingBoundingBoxes = new ArrayList();
        int minX = MathHelper.floor_double(axisalignedbb.minX);
        int maxX = MathHelper.floor_double(axisalignedbb.maxX + 1.0D);
        int minY = MathHelper.floor_double(axisalignedbb.minY);
        int maxY = MathHelper.floor_double(axisalignedbb.maxY + 1.0D);
        int minZ = MathHelper.floor_double(axisalignedbb.minZ);
        int maxZ = MathHelper.floor_double(axisalignedbb.maxZ + 1.0D);
        for(int i = minX; i < maxX; i++)
        {
            for(int k = minZ; k < maxZ; k++)
            {
                for(int j = minY - 1; j < maxY; j++)
                {
                    Block block = Block.blocksList[getBlockId(i, j, k)];
                    if(block != null)
                    {
                        block.getCollidingBoundingBoxes(this, i, j, k, axisalignedbb, collidingBoundingBoxes);
                    }
                }

            }

        }
        return collidingBoundingBoxes;
    }


}
